using System.Windows.Media;
using DimensionsHelper.Client.Helpers;
using DimensionsHelper.Common.Contracts;
using DimensionsHelper.Common.Contracts.TableFormatter.Options;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.TableFormatter;

namespace DimensionsHelper.Client.ViewModels.CsvFormatter;

public partial class TableStyleOptionsViewModel
    : ObservableObject, IRangeStyleOptions, IProjectOption<TableOptions>
{
    private readonly CsvFormatterViewModel _project;


    [ObservableProperty]
    private bool _addAroundBorder;


    [ObservableProperty]
    private bool _addHorizontalBorder;


    [ObservableProperty]
    private bool _addVerticalBorder;


    [ObservableProperty]
    private string _baseFeature = TableFormatterDefaultValues.BaseFeature;


    [ObservableProperty]
    private bool _bold;


    [ObservableProperty]
    private BorderStyle _borderStyle = BorderStyle.None;


    [ObservableProperty]
    private bool _correctTableNumber;


    // Current

    [ObservableProperty]
    private IFontStyleOptions _currentFont;

    [ObservableProperty]
    private IRangeStyleOptions _currentRange;

    //


    [ObservableProperty]
    private string _endFeature = TableFormatterDefaultValues.TableEndFeature;


    [ObservableProperty]
    private double _firstColumnWidth;


    [ObservableProperty]
    private double _fixedColumnWidth;


    [ObservableProperty]
    private Brush _fontColorBrush = Brushes.Black;


    [ObservableProperty]
    private FontFamilyInfo _fontFamily = FontFamilyHelper.DefaultFontFamily;


    [ObservableProperty]
    private double _fontSize = TableFormatterDefaultValues.FontSize;


    [ObservableProperty]
    private ExcelHAlign _hAlign;


    [ObservableProperty]
    private bool _hAlignCenter;


    [ObservableProperty]
    private bool _hAlignLeft = true;


    [ObservableProperty]
    private bool _hAlignRight;


    [ObservableProperty]
    private Brush _interiorBrush = Brushes.Transparent;


    [ObservableProperty]
    private int _intervalRows;


    [ObservableProperty]
    private bool _italic;


    [ObservableProperty]
    private int _maxEmptyRows;


    [ObservableProperty]
    private bool _mergeHeader;


    [ObservableProperty]
    private bool _mergeHeaderEmptyRow;


    [ObservableProperty]
    private bool _mergeTopLeftCells;


    [ObservableProperty]
    private string _numberFormatLocal = string.Empty;


    [ObservableProperty]
    private bool _readSection;


    [ObservableProperty]
    private bool _removeHeaderEmptyRow;


    [ObservableProperty]
    private bool _removeHeaderSpec;


    [ObservableProperty]
    private bool _removeTailSpec;


    [ObservableProperty]
    private bool _removeTitleFeature;


    [ObservableProperty]
    private string _sectionFeature = "[]";


    [ObservableProperty]
    private string _sectionLeftFeature = "[";


    [ObservableProperty]
    private string _sectionRightFeature = "]";


    [ObservableProperty]
    private bool _showSection;


    [ObservableProperty]
    private bool _sideColorIgnoreEmptyCell;


    [ObservableProperty]
    private bool _sigColorIgnoreEmptyCell;


    [ObservableProperty]
    private string _tableNumberFeature = TableFormatterDefaultValues.TableNumberFeature;


    [ObservableProperty]
    private string _tableNumberFormat = TableFormatterDefaultValues.TableNumberFormat;


    [ObservableProperty]
    private string _titleFeature = TableFormatterDefaultValues.TableTitleFeature;


    [ObservableProperty]
    private int _titleOffset;


    [ObservableProperty]
    private bool _underlined;


    [ObservableProperty]
    private UnderLineType _underLineType;


    private bool _updateInternal;


    [ObservableProperty]
    private ExcelVAlign _vAlign;


    [ObservableProperty]
    private bool _vAlignBottom;


    [ObservableProperty]
    private bool _vAlignCenter;


    [ObservableProperty]
    private bool _vAlignTop = true;


    [ObservableProperty]
    private bool _wrapText;


    public TableStyleOptionsViewModel(IServiceProvider serviceProvider)
    {
        _project = serviceProvider.GetRequiredService<CsvFormatterViewModel>();
        HeaderStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        SectionStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        SectionMemberStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        TitleStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        SideStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        BaseLabelStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        BaseValueStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        DataStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        InnerTextStyle = serviceProvider.GetRequiredService<RangeStyleOptionsViewModel>();
        HyperlinkStyle = serviceProvider.GetRequiredService<FontStyleOptionsViewModel>();
        Sig = serviceProvider.GetRequiredService<SigCharOptionsViewModel>();

        _currentFont = this;
        _currentRange = this;

        PropertyChanged += OnOptionsPropertyChanged;

        Ranges =
        [
            HeaderStyle,
            TitleStyle,
            SideStyle,
            SectionStyle,
            SectionMemberStyle,
            BaseLabelStyle,
            BaseValueStyle,
            DataStyle,
            InnerTextStyle,
            Sig.SigMarkRowStyle,
            Sig.SigResultStyle
        ];
    }

    public RangeStyleOptionsViewModel HeaderStyle { get; }

    public RangeStyleOptionsViewModel SectionStyle { get; }

    public RangeStyleOptionsViewModel SectionMemberStyle { get; }

    public RangeStyleOptionsViewModel TitleStyle { get; }

    public RangeStyleOptionsViewModel SideStyle { get; }

    public RangeStyleOptionsViewModel BaseLabelStyle { get; }

    public RangeStyleOptionsViewModel BaseValueStyle { get; }

    public RangeStyleOptionsViewModel DataStyle { get; }

    public RangeStyleOptionsViewModel InnerTextStyle { get; }

    public SigCharOptionsViewModel Sig { get; }

    public FontStyleOptionsViewModel HyperlinkStyle { get; }
    
    private IRangeStyleOptions[] Ranges { get; }


    public bool TryWriteOption(TableOptions target)
    {
        target.IntervalRows = IntervalRows;
        target.TitleFeature = TitleFeature;
        target.RemoveTitleFeature = RemoveTitleFeature;
        target.EndFeature = EndFeature;
        target.BaseFeature = BaseFeature;
        target.ReadSection = ReadSection;
        target.SectionFeature = SectionFeature.Length > 1
            ? new TableSectionFeature { Left = SectionFeature[0].ToString(), Right = SectionFeature[1].ToString() }
            : new TableSectionFeature { Left = "[", Right = "]" };
        target.ShowSection = ShowSection;
        target.Font.FontFamily = FontFamily.Name;
        target.Font.FontSize = (float)FontSize;
        target.HAlign = HAlign;
        target.VAlign = VAlign;
        target.InteriorColor = ((SolidColorBrush)InteriorBrush).Color.ToExcelStyleColor();
        target.BorderStyle = BorderStyle;

        if (AddHorizontalBorder)
        {
            target.BorderPosition |= BorderPosition.Horizontal;
        }

        if (AddVerticalBorder)
        {
            target.BorderPosition |= BorderPosition.Vertical;
        }

        if (AddAroundBorder)
        {
            target.BorderPosition |= BorderPosition.Around;
        }

        target.TitleOffset = TitleOffset;
        target.MergeHeader = MergeHeader;
        target.MergeHeaderEmptyRow = MergeHeaderEmptyRow;
        target.RemoveHeaderEmptyRow = RemoveHeaderEmptyRow;
        target.SideColorIgnoreEmpty = SideColorIgnoreEmptyCell;
        target.MaxEmptyRows = MaxEmptyRows;
        target.MergeTopLeftCells = MergeTopLeftCells;
        target.RemoveHeaderSpec = RemoveHeaderSpec;
        target.RemoveTailSpec = RemoveTailSpec;
        target.CorrectTableNumber = CorrectTableNumber;
        target.TableNumberFeature = TableNumberFeature;
        target.TableNumberFormat = TableNumberFormat;

        target.FirstColumnWidth = FirstColumnWidth;
        target.FixedColumnWidth = FixedColumnWidth;

        return HeaderStyle.TryWriteOption(target.HeaderStyleOptions)
               && TitleStyle.TryWriteOption(target.TitleStyleOptions)
               && SideStyle.TryWriteOption(target.SideStyleOptions)
               && SectionStyle.TryWriteOption(target.SectionStyleOptions)
               && SectionMemberStyle.TryWriteOption(target.SectionMemberStyleOptions)
               && BaseLabelStyle.TryWriteOption(target.BaseLabelStyleOptions)
               && BaseValueStyle.TryWriteOption(target.BaseValueStyleOptions)
               && DataStyle.TryWriteOption(target.DataStyleOptions)
               && InnerTextStyle.TryWriteOption(target.InnerTextStyleOptions)
               && HyperlinkStyle.TryWriteOption(target.HyperlinkStyleOptions);
    }

    public void LoadOption(TableOptions tableOptions)
    {
        IntervalRows = tableOptions.IntervalRows;
        TitleFeature = tableOptions.TitleFeature;
        RemoveTitleFeature = tableOptions.RemoveTitleFeature;
        EndFeature = tableOptions.EndFeature;
        BaseFeature = tableOptions.BaseFeature;
        ReadSection = tableOptions.ReadSection;
        SectionFeature = tableOptions.SectionFeature.ToString();
        ShowSection = tableOptions.ShowSection;

        if (!FontFamilyHelper.TryGetFontFamilyInfo(tableOptions.Font.FontFamily, out FontFamilyInfo? info))
        {
            info = FontFamilyHelper.DefaultFontFamily;
            _project?.ReportService?.Warn("'{0}'不是有效的字体名，修改为默认值'{1}'", tableOptions.Font.FontFamily, info.Name);
        }

        FontFamily = info;
        FontSize = tableOptions.Font.FontSize;
        HAlign = tableOptions.HAlign;
        VAlign = tableOptions.VAlign;
        InteriorBrush = new SolidColorBrush(tableOptions.InteriorColor.ToColor());
        BorderStyle = tableOptions.BorderStyle;
        AddAroundBorder = tableOptions.BorderPosition.HasFlag(BorderPosition.Around);
        AddHorizontalBorder = tableOptions.BorderPosition.HasFlag(BorderPosition.Horizontal);
        AddVerticalBorder = tableOptions.BorderPosition.HasFlag(BorderPosition.Vertical);
        TitleOffset = tableOptions.TitleOffset;
        MergeHeader = tableOptions.MergeHeader;
        MergeHeaderEmptyRow = tableOptions.MergeHeaderEmptyRow;
        RemoveHeaderEmptyRow = tableOptions.RemoveHeaderEmptyRow;
        SideColorIgnoreEmptyCell = tableOptions.SideColorIgnoreEmpty;
        MaxEmptyRows = tableOptions.MaxEmptyRows;
        MergeTopLeftCells = tableOptions.MergeTopLeftCells;
        RemoveHeaderSpec = tableOptions.RemoveHeaderSpec;
        RemoveTailSpec = tableOptions.RemoveTailSpec;
        CorrectTableNumber = tableOptions.CorrectTableNumber;
        TableNumberFeature = tableOptions.TableNumberFeature;
        TableNumberFormat = tableOptions.TableNumberFormat;

        HyperlinkStyle.LoadOption(tableOptions.HyperlinkStyleOptions);
        HeaderStyle.LoadOption(tableOptions.HeaderStyleOptions);
        TitleStyle.LoadOption(tableOptions.TitleStyleOptions);
        SideStyle.LoadOption(tableOptions.SideStyleOptions);
        SectionStyle.LoadOption(tableOptions.SectionStyleOptions);
        SectionMemberStyle.LoadOption(tableOptions.SectionMemberStyleOptions);
        BaseLabelStyle.LoadOption(tableOptions.BaseLabelStyleOptions);
        BaseValueStyle.LoadOption(tableOptions.BaseValueStyleOptions);
        DataStyle.LoadOption(tableOptions.DataStyleOptions);
        InnerTextStyle.LoadOption(tableOptions.InnerTextStyleOptions);
    }


    private void SetRangesValue<T>(Action<IRangeStyleOptions, T> setter, T value,
        params IRangeStyleOptions[] exceptions)
    {
        foreach (IRangeStyleOptions range in Ranges)
        {
            if (Array.IndexOf(exceptions, range) > -1)
            {
                continue;
            }

            setter(range, value);
        }
    }


    private void SetFontsValue<T>(Action<IFontStyleOptions, T> setter, T value)
    {
        SetRangesValue(setter, value);
        setter(Sig.UpperCaseStyle, value);
        setter(Sig.LowerCaseStyle, value);
    }


    private void OnOptionsPropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (_updateInternal)
        {
            return;
        }

        switch (e)
        {
            case { PropertyName: nameof(FontFamily) }:
            {
                SetFontsValue(static (range, value) => range.FontFamily = value, FontFamily);
                break;
            }

            case { PropertyName: nameof(FontSize) }:
            {
                SetFontsValue(static (range, value) => range.FontSize = value, FontSize);
                break;
            }

            case { PropertyName: nameof(Bold) }:
            {
                SetFontsValue(static (range, value) => range.Bold = value, Bold);
                break;
            }

            case { PropertyName: nameof(Italic) }:
            {
                SetFontsValue(static (range, value) => range.Italic = value, Italic);
                break;
            }

            case { PropertyName: nameof(Underlined) }:
            {
                SetFontsValue(static (range, value) => range.Underlined = value, Underlined);
                break;
            }

            case { PropertyName: nameof(UnderLineType) }:
            {
                SetFontsValue(static (range, value) => range.UnderLineType = value, UnderLineType);
                break;
            }

            case { PropertyName: nameof(FontColorBrush) }:
            {
                SetFontsValue(static (range, value) => range.FontColorBrush = value, FontColorBrush);
                break;
            }

            case { PropertyName: nameof(HAlignLeft) }:
            {
                _updateInternal = true;

                if (HAlignLeft)
                {
                    HAlignCenter = false;
                    HAlignRight = false;
                }
                else
                {
                    HAlignLeft = true;
                }

                HAlign = ExcelHAlign.Left;
                SetRangesValue(static (range, value) => range.HAlignLeft = value, HAlignLeft, SectionStyle,
                    SectionMemberStyle);

                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(HAlignCenter) }:
            {
                _updateInternal = true;

                if (HAlignCenter)
                {
                    HAlignLeft = false;
                    HAlignRight = false;
                    HAlign = ExcelHAlign.Center;
                }
                else
                {
                    HAlignLeft = true;
                    HAlign = ExcelHAlign.Left;
                }

                SetRangesValue(static (range, value) => range.HAlignCenter = value, HAlignCenter, SectionStyle,
                    SectionMemberStyle);

                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(HAlignRight) }:
            {
                _updateInternal = true;

                if (HAlignRight)
                {
                    HAlignLeft = false;
                    HAlignCenter = false;
                    HAlign = ExcelHAlign.Right;
                }
                else
                {
                    HAlignLeft = true;
                    HAlign = ExcelHAlign.Left;
                }

                SetRangesValue(static (range, value) => range.HAlignRight = value, HAlignRight, SectionStyle,
                    SectionMemberStyle);

                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(VAlignTop) }:
            {
                _updateInternal = true;

                if (VAlignTop)
                {
                    VAlignCenter = false;
                    VAlignBottom = false;
                }
                else
                {
                    VAlignTop = true;
                }

                VAlign = ExcelVAlign.Top;

                SetRangesValue(static (range, value) => range.VAlignTop = value, VAlignTop, SectionStyle,
                    SectionMemberStyle);
                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(VAlignCenter) }:
            {
                _updateInternal = true;

                if (VAlignCenter)
                {
                    VAlignTop = false;
                    VAlignBottom = false;
                    VAlign = ExcelVAlign.Center;
                }
                else
                {
                    VAlignTop = true;
                    VAlign = ExcelVAlign.Top;
                }

                SetRangesValue(static (range, value) => range.VAlignCenter = value, VAlignCenter, SectionStyle,
                    SectionMemberStyle);
                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(VAlignBottom) }:
            {
                _updateInternal = true;

                if (VAlignBottom)
                {
                    VAlignTop = false;
                    VAlignCenter = false;
                    VAlign = ExcelVAlign.Bottom;
                }
                else
                {
                    VAlignTop = true;
                    VAlign = ExcelVAlign.Top;
                }

                SetRangesValue(static (range, value) => range.VAlignBottom = value, VAlignBottom, SectionStyle,
                    SectionMemberStyle);
                _updateInternal = false;
                break;
            }

            case { PropertyName: nameof(AddAroundBorder) }:
            {
                SetRangesValue(static (range, value) => range.AddAroundBorder = value, AddAroundBorder, TitleStyle,
                    SectionStyle, SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(AddHorizontalBorder) }:
            {
                SetRangesValue(static (range, value) => range.AddHorizontalBorder = value, AddHorizontalBorder,
                    TitleStyle, SectionStyle, SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(AddVerticalBorder) }:
            {
                SetRangesValue(static (range, value) => range.AddVerticalBorder = value, AddVerticalBorder,
                    TitleStyle, SectionStyle, SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(BorderStyle) }:
            {
                SetRangesValue(static (range, value) => range.BorderStyle = value, BorderStyle, TitleStyle,
                    SectionStyle, SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(WrapText) }:
            {
                SetRangesValue(static (range, value) => range.WrapText = value, WrapText, TitleStyle, SectionStyle,
                    SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(InteriorBrush) }:
            {
                SetRangesValue(static (range, value) => range.InteriorBrush = value, InteriorBrush, TitleStyle,
                    SectionStyle, SectionMemberStyle);
                break;
            }

            case { PropertyName: nameof(SectionFeature) }:
            {
                string currentSectionFeature = SectionFeature;

                if (currentSectionFeature.Length >= 2)
                {
                    SectionLeftFeature = currentSectionFeature[0].ToString();
                    SectionRightFeature = currentSectionFeature[1].ToString();
                }

                break;
            }

            case { PropertyName: nameof(MergeHeaderEmptyRow) }:
            {
                if (MergeHeaderEmptyRow)
                {
                    _updateInternal = true;
                    RemoveHeaderEmptyRow = false;
                    _updateInternal = false;
                }

                break;
            }

            case { PropertyName: nameof(RemoveHeaderEmptyRow) }:
            {
                if (RemoveHeaderEmptyRow)
                {
                    _updateInternal = true;
                    MergeHeaderEmptyRow = false;
                    _updateInternal = false;
                }

                break;
            }
        }
    }
}